from wineObjects import BottleBase, Tasting, colors
import datetime

class Bottle(BottleBase):
    parentArea = None
    
    def __init__(self,**args):
        for k,v in args.iteritems():
            setattr(self,k,v)

    def __getstate__(self):
        #print 'pickcling ',self , '  ',self.name ,self.__dict__
        self.__dict__.pop('parentArea')
        return self.__dict__

    def dump(self,i=0):
        print '***'*i,'%15s, %15s %20s %20s'%(self.country, self.region,
                                      self.appellation,
                                      self.cru_name,)


    def numTastings(self):
        try:
            return len(self.tastings)
        except:
            return 0

    def compare(self,o,d):
        ok = True
        for att in self._wineAttributes:
            if att in ('tastings','bottleId', 'lastUpdate'):
                continue
            ok_att = (getattr(self,att) == getattr(o,att) )
            ok = ok and ok_att
            if not ok_att:
                d[self].append(att)

        differing_tast = self.compareTasting(o)
        if differing_tast != []:
            d[self].append('_tastings_')
            ok = False
        return ok

    def regId(self):
        return (self.country, self.region, self.appellation) #, self.cru_name, self.millesime)


        
    def equals(self,o):
        ok = (self.regId() == o.regId() ) and (self.millesime == o.millesime)
        if ok :
            r=difflib.get_close_matches(self.cru_name, [o.cru_name], 1, cutoff=0.7)
            #print '         --- ',r
            ok = ok and len(r) >0
        return ok

    def replaceBy(self, o, useSelfParent = False):
        myParent = self.parentArea
        oParent = o.parentArea
        myParent.wines.remove(self)
        myParent.wines.append(o)
        if useSelfParent:
            o.parentArea = myParent
        
            
    def updateFrom(self, o):
        for att in self._wineAttributes:
            if att in ('tastings','bottleId', 'lastUpdate'):
                continue
            ov = getattr(o,att)
            if ov != getattr(self,att):
                setattr(self,att,ov)

        # deal with tastings

    def toDict(self):
        d = {}
        for k in BottleBase._wineAttributes :
            v = getattr(self, k ) 
            if v != None:
                d[k]=v
        return d

    @staticmethod
    def buildFromDict( d, parent ):
        b = Bottle(parentArea = parent, **d)
        if b.tastings :
            #b.tastingsFromDict()
            for t in b.tastings:
                t.bottle = b
        return b
    

    def fromDict(self,d):
        for k,v in d.iteritems():
            setattr(self,k,v)
        #print 'from dict ', self.cru_name, ' ',self.tastings
        if self.tastings :
            t.bottle = self
            
        
    def areaInheritance(self):
        return [self]+self.parentArea.areaInheritance()


    def removeTasting(self, t):
        self.tastings.remove(t)
        if self.removedTastings == []:
            self.removedTastings = []
        self.removedTastings += [t.tastingId]
        self.updateRate()

    def addTasting(self, t):
        self.tastings.append(t)
        if not t.tastingId:
            t.tastingId = timeId()
        self.updateRate()
        
    def updateRate(self):
        tastings = self.tastings
        self.meanrate = sum( t.rate for t in tastings)/len(tastings)

    def diff(self,b):
        _sd = '%20s    %30s  |  %30s'
        lt = lambda a: len(a) if a else 0
        print _sd%('difference ', self.cru_name, b.cru_name), '  ntastings = ',lt(self.tastings), ' , ', lt(b.tastings)
        differing_att = []
        for att in self._wineAttributes:
            if att in ('tastings' , 'lastUpdate'):
                continue
            att_s, att_b = getattr(self, att), getattr(b, att)
            if att_b != att_s:
                print _sd%(att , att_s , att_b)
                differing_att.append(att)

        differing_tast = self.compareTasting(b)
        
        print ' tastings diff ', differing_tast
        print        
        return differing_att, differing_tast

    def compareTasting(self, b):
        """ returns a list [ [t1,t2] , [t1,t2],... ] for each differing pair of tastings within self and b
        t1 xor t2 is None if missing.
        """
        # dict of tasting, keys are tastingId, values are [a,b]
        tastingD = {}        
        if self.tastings:
            for t in self.tastings:
                tastingD[t.tastingId] = [t,None]
        if b.tastings:
            for t in b.tastings:
                l = tastingD.get(t.tastingId, [None,None])
                t0 = l[0]
                if t0 :
                    if t0.compare(t) :
                        l[0]=None # compared ok, l will be [None,None]
                    else:
                        l[1] = t
                else:
                    l[1]= None
        differing_tast = [ v for v in tastingD.values() if v != [None, None] ]
        return differing_tast
    
    def _tastingId(self):
        i = random.randint(0,10e6)
        while i in [t.tastingId for t in self.tastings]:
            i = random.randint()
        return i

    def requestSaveContent(self, filename=''):
        self.parentArea.requestSaveContent(filename) # for now just forward to parent


    def touch(self):
        self.lastUpdate = datetime.datetime.now()


    
    def compactString(self):
        """Return the compact string associated to this bottle. Used for quick searches """
        if self._compactString :
            return self._compactString
        self._compactString = self.compactStringBuilder(self)
        return self._compactString

    compactStringBuilder = None
    def compactStringBuilder_cru_app(self):
        return self.cru_name.lower()+self.appellation.lower()
